﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Pahan.McuFusion.Common;
using Pahan.McuFusion.Common.Utils;
using Pahan.McuFusion.UI.Interfaces;
using Pahan.McuFusion.UI.Interfaces.NewWorkspaceWizardPages;
using Pahan.McuFusion.UI.Views.NewWorkspaceWizardPages;
using Pahan.McuFusion.UI.Workspaces;

namespace Pahan.McuFusion.UI.Presenters
{
    public class NewWorkspaceWizardPresenter
    {
        #region Constructors

        public NewWorkspaceWizardPresenter(IWizardView view)
        {
            this.view = view;
            view.Title = "New Workspace Wizard";
            view.CanGoBack = false;
            view.CanGoNext = true;
            view.CanFinish = false;
            view.CanCancel = true;
            view.BackClicked += OnBackClicked;
            view.NextClicked += OnNextClicked;
            view.FinishClicked += OnFinishClicked;

            welcomePage = new WelcomePage();
            programmerPage = new ProgrammerPage();
            hardwareAdapterPage = new HardwareAdapterPage();
            hardwareInterfacePage = new HardwareInterfacePage();
            summaryPage = new SummaryPage();
            
            programmerPage.SelectedProgrammerChanged += OnSelectedProgrammerChanged;
            programmerPage.SelectedMicrocontrollerChanged += OnSelectedMicrocontrollerChanged;
            programmerPage.ShowProgrammers(GetProgrammers());

            hardwareAdapterPage.SelectedAdapterChanged += OnSelectedAdapterChanged;

            hardwareInterfacePage.SelectedInterfaceChanged += OnSelectedInterfaceChanged;

            view.CurrentPage = welcomePage;
        }

        #endregion

        #region Public Methods

        public bool ShowWizard()
        {
            bool result = view.Show();
            if (result)
            {
                CreateWorkspace();
            }
            return result;
        }

        #endregion

        #region Public Properties

        public Workspace Workspace
        {
            get;
            private set;
        }

        #endregion

        #region Private Methods

        #region Steps

        private void OnFinishClicked(object sender, EventArgs e)
        {
            view.Close(true);
        }

        private void OnNextClicked(object sender, EventArgs e)
        {
            if (view.CurrentPage == welcomePage)
            {
                GoToProgrammerPage();
            }
            else if (view.CurrentPage == programmerPage)
            {
                GoToHardwareInterfacePage();
            }
            else if (view.CurrentPage == hardwareInterfacePage)
            {
                if (GetAdapters().Count != 1)
                {
                    GoToHardwareAdapterPage();
                }
                else
                {
                    GoToSummaryPage();
                }
            }
            else if (view.CurrentPage == hardwareAdapterPage)
            {
                GoToSummaryPage();
            }
        }

        private void OnBackClicked(object sender, EventArgs e)
        {
            if (view.CurrentPage == summaryPage)
            {
                if (GetAdapters().Count != 1)
                {
                    GoToHardwareAdapterPage();
                }
                else
                {
                    GoToHardwareInterfacePage();
                }
            }
            else if (view.CurrentPage == hardwareAdapterPage)
            {
                GoToHardwareInterfacePage();
            }
            else if (view.CurrentPage == hardwareInterfacePage)
            {
                GoToProgrammerPage();
            }
        }

        private void GoToProgrammerPage()
        {
            view.CurrentPage = programmerPage;
            view.CanGoBack = false;
            view.CanGoNext =
                programmerPage.SelectedProgrammer != null &&
                programmerPage.SelectedMicrocontroller != null;
            view.CanFinish = false;
        }

        private void GoToHardwareAdapterPage()
        {
            view.CurrentPage = hardwareAdapterPage;
            view.CanGoBack = true;
            view.CanGoNext = hardwareAdapterPage.SelectedAdapter != null;
            view.CanFinish = false;
        }

        private void GoToHardwareInterfacePage()
        {
            view.CurrentPage = hardwareInterfacePage;
            view.CanGoBack = true;
            view.CanGoNext = hardwareInterfacePage.SelectedInterface != null;
            view.CanFinish = false;
        }

        private void GoToSummaryPage()
        {
            summaryPage.Microcontroller = programmerPage.SelectedMicrocontroller;
            summaryPage.Programmer = programmerPage.SelectedProgrammer;
            summaryPage.HardwareAdapter = hardwareAdapterPage.SelectedAdapter;
            summaryPage.HardwareInterface = hardwareInterfacePage.SelectedInterface;
            view.CurrentPage = summaryPage;
            view.CanGoBack = true;
            view.CanGoNext = true;
            view.CanFinish = true;
        }

        #endregion

        #region Programmer Page

        private IList<ProgrammerInfo> GetProgrammers()
        {
            return AssemblyLoader.GetObjects<ProgrammerInfo>();
        }

        private void OnSelectedProgrammerChanged(object sender, EventArgs e)
        {
            programmerPage.ShowMicrocontrollers(
                programmerPage.SelectedProgrammer != null ?
                programmerPage.SelectedProgrammer.SupportedMicrocontrollers :
                new DeviceInfo[0]);
            view.CanGoNext = programmerPage.SelectedProgrammer != null &&
                programmerPage.SelectedMicrocontroller != null;
            if (programmerPage.SelectedProgrammer != null)
            {
                hardwareInterfacePage.ShowInterfaces(GetInterfaces());
                if (hardwareInterfacePage.SelectedInterface != null)
                {
                    hardwareAdapterPage.ShowAdapters(GetAdapters());
                }
            }
        }

        private void OnSelectedMicrocontrollerChanged(object sender, EventArgs e)
        {
            view.CanGoNext = programmerPage.SelectedProgrammer != null &&
                programmerPage.SelectedMicrocontroller != null;
        }

        #endregion

        #region Hardware Adapter Page

        private IList<HardwareAdapterInfo> GetAdapters()
        {
            var adapters = 
                from adapter in AssemblyLoader.GetObjects<HardwareAdapterInfo>()
                where programmerPage.SelectedProgrammer.Supports(adapter)
                where adapter.Supports(hardwareInterfacePage.SelectedInterface)
                select adapter;

            return adapters.ToList();
        }

        private void OnSelectedAdapterChanged(object sender, EventArgs e)
        {
            view.CanGoNext = hardwareAdapterPage.SelectedAdapter != null;
        }

        #endregion

        #region Hardware Interface Page

        private IList<HardwareInterfaceInfo> GetInterfaces()
        {
            var adapters = AssemblyLoader.GetObjects<HardwareAdapterInfo>();
            var interfaces = AssemblyLoader.GetObjects<HardwareInterfaceInfo>();
            var supportedInterfaces =
                from adapter in adapters
                where programmerPage.SelectedProgrammer.Supports(adapter)
                from hwInterface in interfaces
                where adapter.Supports(hwInterface)
                select hwInterface;
            return supportedInterfaces.Distinct().ToList();
        }

        private void OnSelectedInterfaceChanged(object sender, EventArgs e)
        {
            view.CanGoNext = hardwareInterfacePage.SelectedInterface != null;
            if (hardwareInterfacePage.SelectedInterface != null)
            {
                hardwareAdapterPage.ShowAdapters(GetAdapters());
            }
        }

        #endregion

        private void CreateWorkspace()
        {
            this.Workspace = new Workspace(
                summaryPage.Microcontroller,
                summaryPage.Programmer,
                summaryPage.HardwareAdapter,
                summaryPage.HardwareInterface);
        }

        #endregion

        #region Private Fields

        private IWizardView view;

        private readonly IWelcomePage welcomePage;
        private readonly IProgrammerPage programmerPage;
        private readonly IHardwareAdapterPage hardwareAdapterPage;
        private readonly IHardwareInterfacePage hardwareInterfacePage;
        private readonly ISummaryPage summaryPage;

        #endregion

    }
}
